#include "DXUT.h"
#include "EntityAI.h"
#include "../World.h"

EntityAI::EntityAI(const D3DXVECTOR3& pos) : EntityLiving(pos) {

}

EntityAI::EntityAI(const D3DXVECTOR3& pos, const D3DXAABB& aabb) : EntityLiving(pos, aabb) {

}

void EntityAI::OnFrameMove( EntityWorld * pWorld, double fTime, float fElapsedTime) {
	EntityLiving::OnFrameMove(pWorld, fTime, fElapsedTime);
}

/* -----------------------------------------------------------------------------------------------
   -------------------------------------CACTUSMAN-------------------------------------------------
   ----------------------------------------------------------------------------------------------- */

EntityCactusMan::EntityCactusMan(const D3DXVECTOR3& pos) : EntityAI(pos, D3DXAABB(D3DXVECTOR3(-0.4f, -0.0f, -0.4f), D3DXVECTOR3( 0.4f,  1.6f,  0.4f))) {
	m_MoveTime			= 0.0f;
	m_TargetDirection	= D3DXVECTOR3();
}

void EntityCactusMan::OnFrameMove( EntityWorld * pWorld, double fTime, float fElapsedTime) {
	D3DXVECTOR3 pos = m_Position;
	EntityAI::OnFrameMove(pWorld, fTime, fElapsedTime);
	D3DXVECTOR3 dif = pos - m_Position;

	if (D3DXVec3Length(&dif) < fElapsedTime) {
		if (m_Swimming) {
			m_Velocity.y += 5.0f;
			m_Velocity.y = min(m_Velocity.y, 5.0f);
		} else if (m_Grounded) {
			m_Velocity.y += 10.0f;
			m_Velocity.y = min(m_Velocity.y, 15.0f);
		}
	};
	
	if (m_MoveTime > 0.0f) {
		m_Rotation.y = (m_Rotation.y * (1.0f -  5.0f * fElapsedTime)) + (m_TargetDirection.y * 5.0f * fElapsedTime);

		m_MoveTime -= fElapsedTime;
				
		D3DXVECTOR3 dir = D3DXVECTOR3(50.0f * fElapsedTime, 0.0f, 0.0f);
		D3DXMATRIX mRot;
		D3DXMatrixRotationY(&mRot, m_Rotation.y - D3DX_PI / 2.0f);
		D3DXVec3TransformCoord(&dir, &dir, &mRot);

		m_Velocity += dir;
	} else {
		m_MoveTime   = (rand() % 10000) / 1000.0f;
		m_TargetDirection.y = (rand() % 10000) / 1000.0f;
	}
}

void EntityCactusMan::OnD3D11CreateDevice( ID3D11Device* pd3dDevice ) {
	BlockVertex *   vertices	= NULL;
	WORD			vs			= 0;
	WORD *			indices		= NULL;
	WORD			is			= 0;

	CACTUS_BLOCK.GenerateIndexed(&vertices, &vs, &indices, &is);

	BlockVertex *   verticesbuffer	= (BlockVertex *) calloc( vs * 6, sizeof(BlockVertex));

	for (int i = 0; i < 6; i++)
		memcpy(&verticesbuffer[vs * i], vertices, vs * sizeof(BlockVertex));
	
	D3DXMATRIX mMat, mMat1, mMat2;
	D3DXMatrixScaling(&mMat1, 0.40f, 0.60f, 0.20f);
	D3DXMatrixTranslation(&mMat2, 0.00f, 0.30f, 0.00f);
	mMat = mMat1 * mMat2;
	int m = 0;
	for (int i = 0; i < vs; i++)
		D3DXVec3TransformCoord(&verticesbuffer[i + m].Pos, &vertices[i].Pos, &mMat);
	m += vs;

	D3DXMatrixScaling(&mMat1, 0.20f, 0.60f, 0.20f);
	D3DXMatrixTranslation(&mMat2, 0.11f, -0.30f, 0.00f);
	mMat = mMat1 * mMat2;
	for (int i = 0; i < vs; i++)
		D3DXVec3TransformCoord(&verticesbuffer[i + m].Pos, &vertices[i].Pos, &mMat);
	m += vs;

	D3DXMatrixScaling(&mMat1, 0.20f, 0.60f, 0.20f);
	D3DXMatrixTranslation(&mMat2, -0.11f, -0.30f, 0.00f);
	mMat = mMat1 * mMat2;
	for (int i = 0; i < vs; i++)
		D3DXVec3TransformCoord(&verticesbuffer[i + m].Pos, &vertices[i].Pos, &mMat);
	m += vs;

	D3DXMatrixScaling(&mMat1, 0.20f, 0.50f, 0.20f);
	D3DXMatrixTranslation(&mMat2, 0.31f, -0.25f, 0.00f);
	mMat = mMat1 * mMat2;
	for (int i = 0; i < vs; i++)
		D3DXVec3TransformCoord(&verticesbuffer[i + m].Pos, &vertices[i].Pos, &mMat);
	m += vs;

	D3DXMatrixScaling(&mMat1, 0.20f, 0.50f, 0.20f);
	D3DXMatrixTranslation(&mMat2, -0.31f, -0.25f, 0.00f);
	mMat = mMat1 * mMat2;
	for (int i = 0; i < vs; i++)
		D3DXVec3TransformCoord(&verticesbuffer[i + m].Pos, &vertices[i].Pos, &mMat);
	m += vs;

	D3DXMatrixScaling(&mMat1, 0.40f, 0.40f, 0.40f);
	D3DXMatrixTranslation(&mMat2, 0.00f, 0.20f, 0.00f);
	mMat = mMat1 * mMat2;
	for (int i = 0; i < vs; i++)
		D3DXVec3TransformCoord(&verticesbuffer[i + m].Pos, &vertices[i].Pos, &mMat);
	m += vs;
	
	D3D11_BUFFER_DESC bd;
	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( BlockVertex ) * vs * 6;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory( &InitData, sizeof(InitData) );
	InitData.pSysMem = verticesbuffer;
	pd3dDevice->CreateBuffer( &bd, &InitData, &m_pVertexBuffer11 );

	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( WORD ) * is;        // 36 vertices needed for 12 triangles in a triangle list
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.CPUAccessFlags = 0;
	InitData.pSysMem = indices;
	pd3dDevice->CreateBuffer( &bd, &InitData, &m_pIndexBuffer11 );

	m_indexSize = is;
	
	free(vertices);
	free(indices);
	free(verticesbuffer);
}

void EntityCactusMan::OnD3D11FrameRender( const D3DXFRUSTUM frustum, EntityWorld * pWorld, ID3D11DeviceContext* pd3dImmediateContext, double fTime, float fElapsedTime) {
	if (AABBInFrustum(m_BoundingBox.Min + m_Position, m_BoundingBox.Max + m_Position, frustum)) {
		D3DXMATRIX mMat, mMatFinal;
		D3DXMatrixTranslation(&mMat, m_Position.x, m_Position.y, m_Position.z );
		D3DXMATRIX mRot;
		D3DXMatrixRotationY(&mRot, m_Rotation.y);

		mMat = mRot * mMat;

		CB_VS_PER_OBJECT			cb0;
		D3D11_MAPPED_SUBRESOURCE	cbMapped;
		//D3DXMatrixTranspose( &cb0.mWorld, &mMat );
		Block block = pWorld->getBlock(m_Position);
		cb0.lGloballight = D3DXVECTOR4(g_LightLevels[block.skyLight], g_LightLevels[block.blockLight], 0.0f, 0.0f);


		D3DXMatrixTranslation(&mMatFinal, 0.0f, 0.6f, 0.0f );
		mMatFinal = mMat * mMatFinal;
		D3DXMatrixTranspose( &cb0.mWorld, &mMatFinal );
		if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
			CopyMemory(cbMapped.pData, &cb0, sizeof( CB_VS_PER_OBJECT ));
			pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
		}
		//	pd3dImmediateContext->VSSetConstantBuffers( 1, 1, &m_pcbVSPerObject11 );

		UINT stride = sizeof( BlockVertex );
		UINT offset = 0;

		pd3dImmediateContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer11, &stride, &offset );
		pd3dImmediateContext->IASetIndexBuffer( m_pIndexBuffer11, DXGI_FORMAT_R16_UINT, 0 );


		pd3dImmediateContext->DrawIndexed( 36, 0, 0);

		D3DXMatrixRotationX(&mRot, sin(fTime * 10.0f) / 2.0f);
		D3DXMatrixTranslation(&mMatFinal, 0.0f, 0.6f, 0.0f );
		mMatFinal = mRot * mMat * mMatFinal;
		D3DXMatrixTranspose( &cb0.mWorld, &mMatFinal );
		if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
			CopyMemory(cbMapped.pData, &cb0, sizeof( CB_VS_PER_OBJECT ));
			pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
		}

		pd3dImmediateContext->DrawIndexed( 36, 0, 24);

		D3DXMatrixRotationX(&mRot, -sin(fTime * 10.0f) / 2.0f);
		D3DXMatrixTranslation(&mMatFinal, 0.0f, 0.6f, 0.0f );
		mMatFinal = mRot * mMat * mMatFinal;
		D3DXMatrixTranspose( &cb0.mWorld, &mMatFinal );
		if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
			CopyMemory(cbMapped.pData, &cb0, sizeof( CB_VS_PER_OBJECT ));
			pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
		}
		pd3dImmediateContext->DrawIndexed( 36, 0, 48);

		D3DXMatrixRotationX(&mRot, -sin(fTime * 4.0f) / 4.0f);
		D3DXMatrixTranslation(&mMatFinal, 0.0f, 1.2f, 0.0f );
		mMatFinal = mRot * mMat * mMatFinal;
		D3DXMatrixTranspose( &cb0.mWorld, &mMatFinal );
		if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
			CopyMemory(cbMapped.pData, &cb0, sizeof( CB_VS_PER_OBJECT ));
			pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
		}
		pd3dImmediateContext->DrawIndexed( 36, 0, 72);

		D3DXMatrixRotationX(&mRot, sin(fTime * 4.0f) / 4.0f);
		D3DXMatrixTranslation(&mMatFinal, 0.0f, 1.2f, 0.0f );
		mMatFinal = mRot * mMat * mMatFinal;
		D3DXMatrixTranspose( &cb0.mWorld, &mMatFinal );
		if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
			CopyMemory(cbMapped.pData, &cb0, sizeof( CB_VS_PER_OBJECT ));
			pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
		}
		pd3dImmediateContext->DrawIndexed( 36, 0, 96);

		D3DXMatrixTranslation(&mMatFinal, 0.0f, 1.2f, 0.0f );
		mMatFinal = mMat * mMatFinal;
		D3DXMatrixTranspose( &cb0.mWorld, &mMatFinal );
		if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
			CopyMemory(cbMapped.pData, &cb0, sizeof( CB_VS_PER_OBJECT ));
			pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
		}

		pd3dImmediateContext->DrawIndexed( 36, 0, 120);
	}
}